﻿
//	------------------------------------------------------------------------------
//                                       _                          
//              _ __ ___   ___ _ __ ___ | |__  _ __ __ _ _ __   ___ 
//             | '_ ` _ \ / _ \ '_ ` _ \| '_ \| '__/ _` | '_ \ / _ \
//             | | | | | |  __/ | | | | | |_) | | | (_| | | | |  __/
//             |_| |_| |_|\___|_| |_| |_|_.__/|_|  \__,_|_| |_|\___|
//                                                     
//	------------------------------------------------------------------------------

#region - License -
//
//	------------------------------------------------------------------------------                                                   
//	         Copyright (c) 2010 Peter Vyvey (peter.vyvey@chiliware.be)
//	------------------------------------------------------------------------------
//
//
//	This file is part of CHILIWARE MEMBRANE.
//
//	CHILIWARE MEMBRANE is free software: you can redistribute it and/or modify
//	it under the terms of the GNU Lesser General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	CHILIWARE MEMBRANE is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU Lesser General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public License
//	along with CHILIWARE MEMBRANE.  If not, see <http://www.gnu.org/licenses/>.
//
//
#endregion

#region - Changes -
//
//	peter.vyvey@chiliware.be		2010-08-09		Created
//
#endregion

#region - Using -

using System;
using Chiliware.Membrane.Extension;

#endregion

namespace Chiliware.Membrane.ExceptionManagement
{
	#region - ExceptionHandler -

	/// <summary>
	/// Handles exception raised in the ApplicationModel workspace.
	/// </summary>
	public static class ExceptionHandler
    {
        #region - Constants -

		/// <summary>
		/// Template to format the exception.
		/// </summary>
        private const string EXCEPTION_FORMAT = "{0} (Result: 0x{1}). Exception ID: {2}).";

		/// <summary>
		/// Template to format an exception with extended information.
		/// </summary>
        private const string EXCEPTION_FORMAT_EXTENDED = "{4}.\r\n{0}\\{2}\\0x{1}.\r\nException ID: {3}).";

        #endregion

        #region - Public static methods -

		/// <summary>
		/// Formats and handles an exception.
		/// </summary>
		/// <param name="ex">The <see cref="ApplicationModelException"/> to handle.</param>
		/// <returns>A string message that can be send to client applications.</returns>
        public static string FormatServiceException(ApplicationModelException ex)
        {
            return ExceptionHandler.FormatServiceException(ex, false);
        }

		/// <summary>
		/// Formats and handles an exception.
		/// </summary>
		/// <param name="ex">The <see cref="ApplicationModelException"/> to handle.</param>
		/// <param name="isExtended">TRUE if the message should be in extended format, FALSE otherwise.</param>
		/// <returns>A string message that can be send to client applications.</returns>
        public static string FormatServiceException(ApplicationModelException ex, bool isExtended)
        {
            if (isExtended)
            {
                return string.Format(ExceptionHandler.EXCEPTION_FORMAT_EXTENDED, ex.GetType().Name.Humanize(), Enum.Format(typeof(ExceptionNumber), ex.Number, "x"), ex.Number, ex.ID, ex.Message);
            }
            else
            {
                return string.Format(ExceptionHandler.EXCEPTION_FORMAT, ex.GetType().Name.Humanize(), Enum.Format(typeof(ExceptionNumber), ex.Number, "x"), ex.ID);
            }
        }

		/// <summary>
		/// Checks if the exception is handled.
		/// </summary>
		/// <param name="ex">The exception.</param>
		/// <returns>TRUE if the exception if the exception has not been handled, FALSE otherwise.</returns>
		public static bool IsUnhandledException(Exception ex)
		{
			bool isUnhandled = true;

			if (ex is ApplicationModelException)
			{
				ApplicationModelException exceptionWrapper = (ApplicationModelException)ex;
				isUnhandled = exceptionWrapper.IsUnhandled;
			}

			return isUnhandled;
		}

		/// <summary>
		/// Handles an exception and wraps it into an <see cref="ApplicationModelException"/> of type T as needed.
		/// </summary>
		/// <typeparam name="T">The type of <see cref="ApplicationModelException"/> to wrap the original exception into.</typeparam>
		/// <param name="ex">The exception.</param>
		/// <param name="policyName">The name of the exception policy to apply.</param>
		/// <returns>An <see cref="ApplicationModelException"/> of type T.</returns>
		public static T HandleException<T>(Exception ex, string policyName) where T : Exception
		{
			ex.CatchNullArgument("ex");
			policyName.CatchNullOrEmptyArgument("policyName");

			bool shouldWrap = false;

			T outerException = default(T);

			// First handle the execption by 
			//	- logging it to the exception log
			//	- if ex is of type ExceptionWrapper also set the IsUnhandled flag to FALSE
			//	- if ex is NOT of type ExceptionWrapper then just log the exception
			if (ex is ApplicationModelException)
			{
				ApplicationModelException wrapperException = (ApplicationModelException)ex;

				if (wrapperException.IsUnhandled)
				{
					// Write to exception log
					//ExceptionPolicy.HandleException(ex, ExceptionPolicyType.WcfPolicy.ToString());

					// Ok ... this is handled
					wrapperException.IsUnhandled = false;
				}
			}
			else
			{
				// Write to exception log
				//ExceptionPolicy.HandleException(ex, policyName);

				// Only wrap if we have a different type of exception
				shouldWrap = typeof(T) != typeof(Exception);
			}

			if (shouldWrap)
			{
				// Create an instance of the requested ExceptionWrapper subtype
				outerException = (T)Activator.CreateInstance(typeof(T), new object[] { ex.Message, ex });

				// If it is a ExceptionWrapper type also set the IsUnhandled flag to FALSE
				if (outerException is ApplicationModelException)
				{
					(outerException as ApplicationModelException).IsUnhandled = false;
				}
			}

			return outerException;
		}

		#endregion
	}

	#endregion
}
